package com.cby.android.olive.ext

import android.annotation.SuppressLint
import android.content.Context
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.view.Gravity
import android.view.View
import android.view.WindowManager
import android.widget.Toast
import androidx.annotation.StringRes
import androidx.fragment.app.Fragment

/**
 * @description: Toast的全局拓展函数
 *
 * @author ChenBaoyang
 * @date 2021/11/3 17:39
 */




/**
 * [View]全局拓展函数用来[Toast]
 *
 * Context
 * @receiver Context
 * @param text 字符串内容
 */
fun View.showToast(text: String) {
    context.showToast(text)
}

/**
 * [View]全局拓展函数用来[Toast]
 *
 * Context
 * @receiver Context
 * @param resId 字符串资源ID
 */
fun View.showToast(@StringRes resId: Int) {
    context.showToast(resId)
}

/**
 * [View]全局拓展函数用来[Toast]
 *
 * Context
 * @receiver Context
 * @param text 字符串内容
 */
fun View.showLongToast(text: String) {
    context.showLongToast(text)
}

/**
 * [View]全局拓展函数用来[Toast]
 *
 * Context
 * @receiver Context
 * @param resId 字符串资源ID
 */
fun View.showLongToast(@StringRes resId: Int) {
    context.showLongToast(resId)
}


/**
 * [Fragment]全局拓展函数用来[Toast]
 *
 * Context
 * @receiver Context
 * @param text 字符串内容
 */
fun Fragment.showToast(text: String) {
    requireActivity().showToast(text)
}

/**
 * [Fragment]全局拓展函数用来[Toast]
 *
 * Context
 * @receiver Context
 * @param resId 字符串资源ID
 */
fun Fragment.showToast(@StringRes resId: Int) {
    requireActivity().showToast(resId)
}

/**
 * [Fragment]全局拓展函数用来[Toast]
 *
 * Context
 * @receiver Context
 * @param text 字符串内容
 */
fun Fragment.showLongToast(text: String) {
    requireActivity().showLongToast(text)
}

/**
 * [Fragment]全局拓展函数用来[Toast]
 *
 * Context
 * @receiver Context
 * @param resId 字符串资源ID
 */
fun Fragment.showLongToast(@StringRes resId: Int) {
    requireActivity().showLongToast(resId)
}

/**
 * [Context]全局拓展函数用来[Toast]
 *
 * Context
 * @receiver Context
 * @param text 字符串内容
 */
fun Context.showToast(text: CharSequence) {
    Toast.makeText(applicationContext, text, Toast.LENGTH_SHORT).fixBadTokenException().apply { show() }
}

/**
 * [Context]全局拓展函数用来[Toast]
 *
 * Context
 * @receiver Context
 * @param resId 字符串资源ID
 */
fun Context.showToast(@StringRes resId: Int) {
    Toast.makeText(applicationContext, resId, Toast.LENGTH_SHORT).fixBadTokenException().apply { show() }
}

/**
 * [Context]全局拓展函数用来[Toast]
 *
 * Context
 * @receiver Context
 * @param text 字符串内容
 */
fun Context.showLongToast(text: CharSequence) {
    Toast.makeText(applicationContext, text, Toast.LENGTH_LONG).fixBadTokenException().apply { show() }
}

/**
 * [Context]全局拓展函数用来[Toast]
 *
 * Context
 * @receiver Context
 * @param resId 字符串资源ID
 */
fun Context.showLongToast(@StringRes resId: Int) {
    Toast.makeText(applicationContext, resId, Toast.LENGTH_LONG).fixBadTokenException().apply { show() }
}

/**
 * [Context]全局拓展函数用来[Toast]
 *
 * Context
 * @receiver Context
 * @param text 字符串内容
 * @param top 距离顶部距离
 */
fun Context.showShort(text: CharSequence, top: Int) {
    val toast = Toast.makeText(applicationContext,
        text, Toast.LENGTH_SHORT
    ).fixBadTokenException()
    toast.setGravity(Gravity.TOP, 0, top)
    toast.show()
}

/**
 * [Context]全局拓展函数用来[Toast]
 *
 * Context
 * @receiver Context
 * @param resId 字符串资源ID
 * @param top 距离顶部距离
 */
fun Context.showShort(@StringRes resId: Int, top: Int) {
    val toast = Toast.makeText(applicationContext,
        resId, Toast.LENGTH_SHORT
    ).fixBadTokenException()
    toast.setGravity(Gravity.TOP, 0, top)
    toast.show()
}


/**
 * Toast的拓展函数，通过反射方式处理，
 *
 * @receiver Toast
 * @return Toast
 */
fun Toast.fixBadTokenException(): Toast = apply {
    if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N_MR1) {
        try {
            @SuppressLint("DiscouragedPrivateApi")
            val tnField = Toast::class.java.getDeclaredField("mTN")
            tnField.isAccessible = true
            val tn = tnField.get(this)

            val handlerField = tnField.type.getDeclaredField("mHandler")
            handlerField.isAccessible = true
            val handler = handlerField.get(tn) as Handler

            val looper = checkNotNull(Looper.myLooper()) {
                "Can't toast on a thread that has not called Looper.prepare()"
            }
            handlerField.set(tn, object : Handler(looper) {
                override fun handleMessage(msg: Message) {
                    try {
                        handler.handleMessage(msg)
                    } catch (ignored: WindowManager.BadTokenException) {
                    }
                }
            })
        } catch (ignored: IllegalAccessException) {
        } catch (ignored: NoSuchFieldException) {
        }
    }
}